package com.owner.demo.springbootdemo.CircuitBreaker;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.proxy.InvocationHandler;
import org.springframework.cglib.proxy.Proxy;

import java.lang.reflect.Method;

@Slf4j
public abstract class CircuitBreakerRunner<T> implements InvocationHandler {

    private CircuitBreaker breaker;

    private Callable<T> callable;

    public CircuitBreakerRunner(CircuitBreaker breaker, Callable<T> callable) {
        this.breaker = breaker;
        this.callable = callable;
    }

    /**
     * 断路器开启时执行的方法
     * @param o
     * @param method
     * @param args
     * @return
     */
    protected abstract Object fallback(Object o, Method method, Object[] args);

    public Object run() {
        return ((Callable) Proxy.newProxyInstance(this.callable.getClass().getClassLoader(), this.callable.getClass().getInterfaces(), this)).execute();
    }

    @Override
    public Object invoke(Object o, Method method, Object[] args) throws Throwable {
        Object returnValue = null;

        if(breaker.isOpen2Close()){
            //调用成功则进入close状态
            synchronized (this) {
                if (breaker.isOpen2Close()) {
                    breaker.close();
                }
            }
        }

        //判断breaker state
        if(breaker.isOpen()){
            try{
                fallback(o, method, args);
            }catch (Throwable t){
                throw t;
            }
        } else {
            try{
                returnValue = method.invoke(callable, args);
            }catch (Throwable t){
                breaker.incrFailCount();
                if(breaker.isClose2Open()){
                    //触发阈值，打开
                    breaker.open();
                }else{
                    throw t;
                }
            }
        }
        return returnValue;
    }
}
